package org.flexqueries2.utils.events
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	
	[Event(name="everythingReady", type="flash.events.Event")]
	
	public class EventWaiter extends EventDispatcher
	{
		public static const EVERYTHING_READY:String = 'everythingReady'; 
		
		private const INTERNAL_EVENT_RECEIVED:String = 'internalEventReceived';
		
		private var _objects_arr:Array = [];
		
		public function EventWaiter()
		{
		}
		
		/**
		 * Ajoute un objet Ã  attendre
		 */ 
		public function waitFor(object:EventDispatcher, eventName:String):void
		{
			var wo:EventWaiterObject = new EventWaiterObject(object, eventName);
			_objects_arr.push(wo);
			object.addEventListener(eventName, onEventReceived);
			
			dispatchEvent(new Event(INTERNAL_EVENT_RECEIVED));
		}
		
		/**
		 * Indique si tous les Ã©vÃ©nements attendus sont arrivÃ©s
		 */ 
		private function isEverythingFinished():Boolean
		{
			for(var i:Number=0;i<_objects_arr.length;i++)
			{
				if(!_objects_arr[i].isFinished)
					return false;
			}
			
			return true;
		}
		
		[Bindable(event='internalEventReceived')]
		/**
		 * Fournit les Ã©lÃ©ments qui ont envoyÃ© leur Ã©vÃ©nement
		 */ 
		public function get objectsReady():Array
		{
			var arr:Array = [];
			for each(var wo:EventWaiterObject in _objects_arr)
			{
				if(wo.isFinished)
					arr.push(wo);
			}
			return arr;
		}
		
		[Bindable(event='internalEventReceived')]		
		/**
		 * Fournit les Ã©lÃ©ments qui n'ont pas encore envoyÃ© leur Ã©vÃ©nement
		 */ 
		public function get objectsNotReady():Array
		{
			var arr:Array = [];
			for each(var wo:EventWaiterObject in _objects_arr)
			{
				if(!wo.isFinished)
					arr.push(wo);
			}
			return arr;
		}
		
		/**
		 * RÃ©initialise l' EventWaiter
		 */ 
		public function reset():void
		{
			for(var i:Number=0;i<_objects_arr.length;i++)
			{
				EventWaiterObject(_objects_arr[i]).isFinished = false;
				EventWaiterObject(_objects_arr[i]).receivedEvent = null;
				
				dispatchEvent(new Event(INTERNAL_EVENT_RECEIVED));
			}
		}
		
		/**
		 * Retourne un EventWaiterObject Ã  partir de l'objet Ã©coutÃ© et de l'Ã©vÃ©nement attendu
		 */ 		
		private function getEventWaiterObject(object:EventDispatcher, eventName:String):EventWaiterObject
		{
			var wo:EventWaiterObject;
			for(var i:Number=0;i<_objects_arr.length;i++)
			{
				wo = (_objects_arr[i] as EventWaiterObject);
				if(wo.object == object && wo.eventName == eventName)
					return wo;
			}
			
			return null;
		}
		
		
		private function onEventReceived(e:Event):void
		{
			var sourceWO:EventWaiterObject = getEventWaiterObject(e.currentTarget as EventDispatcher, e.type);
			if(sourceWO == null)
				return;
			
			sourceWO.isFinished = true;
			sourceWO.receivedEvent = e;
			
			dispatchEvent(new Event(INTERNAL_EVENT_RECEIVED));
			
			if(isEverythingFinished())
				dispatchEvent(new Event(EventWaiter.EVERYTHING_READY));
		}
		
		
	}
}